home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
tclMotif-1.4
/
doc
/
tclMotif.doc
< prev
next >
Wrap
Text File
|
1995-06-29
|
48KB
|
1,495 lines
<!OPS, Version = 8.0>
<!Page Number Stream,
Name = "page",
Starting Page # = Inherit>
<!Document,
Header Page = no,
Final Output Device = "ps",
Default Printer = "nearest-ps",
Default Page Stream Name = "page">
<!Font Definitions,
F2 = Times 10,
F3 = Times 12,
F4 = Times 12 Italic,
F5 = Times 16 Bold,
F6 = Times 18 Bold,
F7 = Courier 12,
F8 = Times 14 Bold,
F9 = Thames 12,
F10 = Times 6,
F11 = Courier 16 Bold>
<!Page,
Bottom Margin = 1 Inches,
Left Margin = 1 Inches,
Right Margin = 1 Inches,
Hyphenation = on,
Revision Bar Placement = Left>
<!Autonumber Stream, "ref#", 1,
Level 1 Suffix = "">
<!Autonumber Stream, "section#", 1>
<!Autonumber Stream, "list", 1>
<!Autonumber Stream, "footnote", 1,
Level 1 Suffix = "">
<!Autonumber Stream, "Outline", 3,
Level 1 Symbol Type = Upper Roman,
Level 2 Symbol Type = Upper Alpha>
<!Autonumber Stream, "List", 1>
<!Class, "a4:para",
Top Margin = 0.0393701 Inches,
Bottom Margin = 0.0393701 Inches,
Font = F3@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/0.9844442/1.9685042/2.9527555 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize ""a4"")<#0a>
)">
<!Class, "abstract",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 1.50 Inches,
Right Margin = 1.50 Inches,
Alignment = Center,
Font = F4@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum>
<!Class, "abstracthead",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Alignment = Center,
Font = F5@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum>
<!Class, "center",
Top Margin = 0.14 Inches,
Bottom Margin = 0 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Alignment = Center,
Font = F6@Z7@Lam,
Line Spacing = 1.3078 lines,
Left Tab = 0.5/0.5*29 Inches>
<!Class, "left",
Top Margin = 0.14 Inches,
Bottom Margin = 0 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Alignment = Left,
Font = F2@Z7@Lam,
Line Spacing = 1.3067 lines,
Left Tab = 0.5/0.5*29 Inches>
<!Class, "ltr:para",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Font = F3@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize ""ltr"")<#0a>
)">
<!Class, "para",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Font = F3@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum>
<!Class, "program",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 1 Inches,
Right Margin = 0.50 Inches,
Font = F7@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum>
<!Class, "reference",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 1 Inches,
Right Margin = 0.50 Inches,
First Indent = -0.50 Inches,
Font = F3@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum,
Contents = Prefix>
<"|:reference",
Hidden = yes,
Font = @i*,
Subcomponent = yes,
Contents = Shared><F0>[<Autonum, "ref#", 1, Value = "1">]<Tab>
<End Sub><F0>
<!Class, "right",
Top Margin = 0.14 Inches,
Bottom Margin = 0 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Alignment = Right,
Font = F2@Z7@Lam,
Line Spacing = 1.3067 lines,
Left Tab = 0.5/0.5*29 Inches>
<!Class, "section",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Font = F5@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum,
Contents = Prefix>
<"|:section",
Hidden = yes,
Font = @i*,
Subcomponent = yes,
Contents = Shared><F0><Autonum, "section#", 1>
<End Sub><F0>
<!Class, "subsection",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Font = F8@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum>
<!Class, "tbl:autonum",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Alignment = Left,
Font = F9@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/0.8*7 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize nil)<#0a>
)">
<!Class, "tbl:cmpn",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Alignment = Left,
Font = F9@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/0.8*7 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize nil)<#0a>
)">
<!Class, "tbl:frame",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Alignment = Left,
Font = F9@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/0.8*7 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize nil)<#0a>
)">
<!Class, "tbl:pagefor",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Alignment = Left,
Font = F3@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/0.8*7 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize nil)<#0a>
)">
<F10@Z7@Lnl>standard<Tab>ltr<Tab>a4<HR>
top<Tab><Tab><HR>
bottom<Tab><Tab><HR>
left<Tab><Tab><HR>
right<Tab><Tab><HR>
<HR>
<!Class, "tbl:pagenum",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Alignment = Left,
Font = F9@Z7@Lnl,
Line Spacing = 1.1606 lines,
Left Tab = 0/0.8*7 Inches,
Composition = Optimum,
Lisp = "(tell *load-object* mid:put-data 'ileaf::saved-data
'(:form-lang nil :form-pagesize nil)<#0a>
)">
<!Class, "title",
Top Margin = 0.04 Inches,
Bottom Margin = 0.04 Inches,
Left Margin = 0.50 Inches,
Right Margin = 0.50 Inches,
Alignment = Center,
Font = F6@Z7@Lam,
Line Spacing = 1.1615 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum>
<!Class, "|:para",
Top Margin = 0.0266667 Inches,
Bottom Margin = 0.0266667 Inches,
Font = F3@Z7@Lam@i*,
Line Spacing = 1.162 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum,
Contents = Shared>
<!Class, "|:reference",
Top Margin = 0.0266667 Inches,
Bottom Margin = 0.0266667 Inches,
Font = F3@Z7@Lam@i*,
Line Spacing = 1.162 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum,
Contents = Shared>
[<Autonum, "ref#", 1, Value = "1">]<Tab>
<!Class, "|:section",
Top Margin = 0.0266667 Inches,
Bottom Margin = 0.0266667 Inches,
Font = F5@Z7@Lam@i*,
Line Spacing = 1.162 lines,
Left Tab = 0/1*3 Inches,
Composition = Optimum,
Contents = Shared>
<Autonum, "section#", 1>
<!Master Frame,
Name = "At Anchor",
Placement = At Anchor,
Width = 0.41 Inches,
Height = 0.14 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "Auto",
Placement = At Anchor,
Width = 1 Inches,
Height = 0.3329997 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "Bottom",
Placement = Bottom of Page,
Horizontal Alignment = Center,
Width = 6.50 Inches,
Height = 3.25 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "Following Anchor",
Placement = Following Anchor,
Horizontal Alignment = Center,
Width = 6.50 Inches,
Height = 3.25 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "Following Text",
Placement = Following Text,
Horizontal Alignment = Center,
Width = 6.50 Inches,
Height = 3.25 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "Footnote",
Placement = Bottom of Page,
Horizontal Alignment = Left,
Same Page = yes,
Width = 6.50 Inches,
Height = 0.20 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "Top",
Placement = Top of Page,
Horizontal Alignment = Center,
Width = 6.50 Inches,
Height = 3.25 Inches,
Diagram =
V11,
(g9,0,0,)>
<!Master Frame,
Name = "inline",
Placement = At Anchor,
Width = 0.50 Inches,
Height = 0.1660002 Inches,
Diagram =
V11,
(g9,0,0,
(E16,0,0,,5,1,1,0.0533333,1,15,0,0,1,0,0,0,1,5,127,7,0,0,7,0,1,1,0.0666667,0.06
66667,6,6,0,0.0666667,6))>
<Page Header, Frame =
V11,
(g9,0,0,)>
<Page Footer, Frame =
V11,
(g9,1,0,
(t14,1,0,,0,0.5333333,0,7,0,0,,wst:timsps12,)
(t14,2,4,,3.2466667,0.5333333,1,7,0,0,,wst:timsps10,-\ \X80a0\ -))>
<!End Declarations>
<"title">
<|,"1">A Tcl Binding to Motif
<"title">
Jan Newmarch<HR>
University of Canberra
<"abstracthead">
Abstract
<"abstract",
Alignment = Both>
Tcl is a type-free interpreted language intended for <SR>
use as an embedded command language for applica<SR>
tions. Motif is the standard GUI for the X Window Sys<SR>
tem, but this has a complex C-based API. This paper <SR>
discusses a binding of tcl to Motif which allows for a <SR>
simpler API.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, First = Yes, Value = "1.">
<End Sub><F0>Introduction
<"para">
The X Window System is now accepted as the standard windowing systems
for Unix <SR>
graphics workstations and terminals. It provides a low-level set of
tools to build ap<SR>
plications. Most applications now are built using a higher-level toolkit
which typi<SR>
cally supplies objects usually known as widgets. There are a number
of such toolkits, <SR>
but the one that has achieved the major success is the Motif toolkit
based on the Xt <SR>
Intrinsics. Motif has defined a look-and-feel that is copied to a
greater or lesser ex<SR>
tent by other toolkits, and forms a component of specifications such
as COSE.
<"para">
The specification for Motif basically assumes a C-like language, and
the only imple<SR>
mentation of that specification is the C library from OSF. This has
led to many bind<SR>
ings to this library from alternative systems. These include C++,
Ada, Prolog, Lisp, <SR>
Poplog and the Korn Shell.
<"para">
Tcl (Tool Command Language) is a type-free interpreted language that
was designed <SR>
to be embedded into applications requiring a command language for
communication <SR>
with users, to parse specification files requiring language complexity,
and to provide <SR>
a macro language for applications such as spreadsheets. The intent
was to do it right <SR>
once, so that application-writers need not invent their own language
and write their <SR>
own parsers and semantic evaluators.
<"para">
Tcl has been extended with an X Window toolkit not based on the Intrinsics,
that sup<SR>
plies a set of widgets directly accessible from tcl. This Tk toolkit
is generally run <SR>
from a program called wish that sets up a suitable environment and
then calls an event <SR>
processing loop for the Tk widgets.
<"para">
However, there are differences between Tk and Motif, some minor and
some major. <SR>
These differences are no better nor worse than the differences between
other toolkits <SR>
such as InterViews, but do seem to give rise to some heated debate
at times. For ex<SR>
ample, there is the claim that Motif must be slower than Tk because
of the complexity <SR>
of implementation above Xt. On the other hand, it must be faster because
Tcl/Tk is <SR>
interpreted. Tcl/Tk programs are often pointed at as significantly
shorter than equiva<SR>
lent Motif programs, without determining whether this difference is
caused by choice <SR>
of language - C versus Tcl, or choice of toolkit - Motif versus Tk.
Other issues such <SR>
as the complexity of Motif XmStrings against their value for internationalisati
on are <SR>
often discussed.
<"para">
<|,"2">This paper reports on a project that attempts to remove some
of the variables from <SR>
this debate. It provides a binding of Tcl to Motif so that Tcl programs
can be written <SR>
directly using the Motif C libraries. This binding is by a library
of C functions called <SR>
tclMotif (Tcl Motif). The focus in this paper is on the mechanisms of this
implementation.
<"para">
Recently the author became aware of the Wafe system, which was a binding
of the <SR>
Athena widgets to tcl. That project had different aims to this one,
but there are many <SR>
common elements. This is also discussed.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "2.">
<End Sub><F0>Elements of tcl
<"para">
Tcl is an interpreted language with a single data type, string.
It is a command language, that is intended to be embedded into
applications requiring a simple language interface.
The syntax is a cross between `C' and the Unix shells, and it is a simple
and easy language to learn.
A typical program is the following, to find the maximum integer from a list
read in from standard input, one per line:
<"para">
proc max {a b} {<HR>
<tab>if {$a > $b} return $a<HR>
<tab>return $b<HR>
}<HR>
<HR>
gets stdin maximum<HR>
while {[gets stdin next] != -1} {<HR>
<tab>set maximum [max $maximum $next]<HR>
}<HR>
puts stdout "maximum value is $maximum"<HR>
<"para">
Tcl is implemented as a library of `C' functions that can be linked in
with an application, often using a simple interpreter loop.
A large number of applications are now available using this command
language.
This reduces the need for the programmer to invent new languages,
and for the user to learn new ones.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "4.">
<End Sub><F0>Elements of Tk
<"para">
Tk is a set of widgets built directly on X.
It is not based on the Intrinsics.
Like tcl, Tk is implemented as a library of `C' functions,
which can be linked with an application.
Thus it forms an embedded windowing library that uses tcl as main
programming language.
<"para">
The majority of Tk applications are written entirely in tcl,
and assume a standard application called wish.
wish is basically just an interpreter that creates the tcl and Tk worlds
and then enters an event loop, processing and despatching events
to the Tk widgets.
The behaviour and apearance of the widgets are described in tcl,
leading to very short and simple X Window programs.
<"para">
Applications requiring more complex behaviour than possible just with
wish and tcl can be built with additional code, incorporating the
wish interpreter as component.
In tcl version 7, a standard way has been defined to create such
extended applications for both tcl and Tk.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "5.">
<End Sub><F0>The <F11@Z7@Lam>moat<F0> Interpreter
<"para">
tclMotif is defined as a set of `C' functions that provide an interface
between tcl and the Motif library.
This set conforms to the extension standard, so acts as an extension
to the basic tcl interpreter. This extension is built as an application
called moat (MOtif and Tcl) and acts in a similar way to wish.
That is, most tclMotif applications can be written entirely in tcl,
but if needed additional functionality can be linked in easily.
<"para">
The moat interpreter sets
up the tclMotif world so that commands are available to initialize
an Xt application <SR>
context, create widgets and enter the Xt event loop. In early versions
the initialisation <SR>
and loop were hidden as in Tk, but this reduced flexibility (such
as being unable to <SR>
set the application class or fallback resources) and failed to
conform to the emerging way
for tcl extensions <SR>
to be added.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "6.">
<End Sub><F0>Creating Widgets
<"para">
Widgets are created using Tcl commands registered with the Tcl interpreter
on initial<SR>
isation. These creation commands follow the design of the Tk system,
in that there <SR>
is one creation command per class of widget. For example,
<"program">
xmLabel .label
<"para">
The widgets form a tree of widgets rooted in `.'. There is only one
application context <SR>
per tcl interpreter but this does not seem to be a restriction.
<"para">
In addition, Motif has a set of dialogs, which are convenience routines
for creating <SR>
a compound widget in a way that is supposed to be invisible to the
C programmer and <SR>
act as though they create single objects. These routines are also
implemented as wid<SR>
get creation functions in tclMotif. It is not hard to ``special case'' some
functions within <SR>
tclMotif to handle these dialogs. Motif also ``special cases'' two common
operations - <SR>
creating a ScrolledList and a ScrolledText widget. This is also handled
by tclMotif. In <SR>
both of these special cases, the parent is brought into the tclMotif system,
and is given a <SR>
unique name. This name is produced from the pathname by introducing
an extra dot <SR>
into the path.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "7.">
<End Sub><F0>Widget Commands
<"para">
When a widget is created two major things occur: an Xt/Motif widget
is created and <SR>
a command with the widget name is added to the Tcl interpreter. This
gives an object-<SR>
<|,"3">oriented flavour to the system in that a widget becomes a command
which is inter<SR>
preted as an object with methods.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "8.">
<End Sub><F0>Widget Methods
<"para">
Each widget has a set of methods applicable to it. In general, most
widgets inherit <SR>
from TmCore. This allows Xt methods such as <"program", Subcomponent = yes>
<F7@Z7@Lam>ManageChild<End Sub><F0> and <"program", Subcomponent = yes><F7@Z7@Lam>
Unmanage<SR>
Child<End Sub><F0> to be handled from one function. The design of
Tcl registers a command han<SR>
dler per command; widgets that have no special methods simply register
the <"program", Subcomponent = yes><F7@Z7@Lam>TmCore<End Sub><F0> <SR>
handler. Widgets with more methods register a different handler which
may call <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>TmCore<End Sub><F0> eventually
in an inheritance chain.
<"para">
Each widget in fact has special methods: the callback procedures for
that class. This <SR>
is handled by <"program", Subcomponent = yes><F7@Z7@Lam>TmCore
<End Sub><F0> rather than in individual command handlers because of
regu<SR>
larities in the implementation of Motif that are better discussed
in the next section. <SR>
Briefly, each callback can be recognised because it ends in the string
``Callback''. <SR>
This can then be added to the Xt widget callbacks using
<"program", Subcomponent = yes><F7@Z7@Lam>XtAddCallback<End Sub><F0>
in the <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>TmCore<End Sub><F0> handler,
without worrying about exactly which callback it is.
<"para">
In C, when a callback is added to a widget a specific C function is
specified that will <SR>
be invoked when the action for that callback occurs. However, we want
a Tcl function <SR>
to be executed. This is easily done by using a generic C callback
function that handles <SR>
every widget, almost without exception. When a callback is added in
Xt, the <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>ClientData<End Sub><F0>
field is set to point to a structure containing the Tcl interpreter
and <SR>
the string that is the Tcl callback function. This gives the generic
C callback function <SR>
enough information to execute the Tcl function.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "9.">
<End Sub><F0>Resource Converters
<"para">
The presence of resource converters within Xt is the key to the ease
with which this <SR>
binding has been implemented. Previous sections have used existing
Tcl/Tk concepts <SR>
(and code) to a large extent. It is now time for Xt to play a significant
part. Xt allows <SR>
users to store resource values in files such as
<"program", Subcomponent = yes><F7@Z7@Lam>.Xdefaults<End Sub><F0>
to control run-time val<SR>
ues for the program. This user-level control is one of the major features
of Xt. The <SR>
resource files contain strings representing the values the user wants.
For example, a <SR>
width may be set to the string ``200". Xt, and all toolkits built
above it, supply ``re<SR>
source converters'' to transform these string values into the internal
data types re<SR>
quired by the program.
<"para">
To perform such conversions, Xt supplies a number of useful functions.
<"program", Subcomponent = yes><F7@Z7@Lam>XtGetRe<SR>
sourceList<End Sub><F0> and <"program", Subcomponent = yes><F7@Z7@Lam>XtGetCons
traintList<End Sub><F0> return lists of resources applicable <SR>
to each class of widget. Elements in these lists are structures that
contain strings rep<SR>
resenting the source and destination types, and the size (in bytes)
of the destination <SR>
type. The string representations allow searches for source types,
and the structure <SR>
when located in the list provides enough information to call
<"program", Subcomponent = yes><F7@Z7@Lam>XtConvertAnd<SR>
Store<End Sub><F0>. This looks up a list of registered converters
and calls the converter function <SR>
if found.
<"para">
This makes one side of this binding trivially simple: if a resource
can be specified <SR>
in a resource file then a converter exists from string to internal
value. The Tcl <"program", Subcomponent = yes><F7@Z7@Lam>set<SR>
Values<End Sub><F0> method simply has to locate the resource in
these resource lists and call <SR>
<|,"4"><"program", Subcomponent = yes><F7@Z7@Lam>XtConvertAndStore
<End Sub><F0>. It can then use <"program", Subcomponent = yes><F7@Z7@Lam>XtSet
Values<End Sub><F0> to install the converted <SR>
value, and Xt and Motif do the rest!
<"para">
This also makes the naming conventions in tcl very easy. Because resources
are spe<SR>
cified as strings, the names can be used by tcl without change. Motif
and Xt are quite consis<SR>
tent in its use of these names (alphabetic only, beginning with a
lower case letter, and <SR>
with other words in the name capitalised). Tk uses this convention
as well, so the sim<SR>
ilarity in programs across the two systems is maintained.
<"para">
Well, it isn't really trivial. Some resources require widget values,
such as edge bind<SR>
ings in Form. tclMotif needs to supply another converter, from TmWidgetName
to Xt <SR>
Widget. This, and similar needs are answered by just adding more converters.
A more <SR>
serious problem is addressed in the next section.
<"para">
The largest amount of work in this binding is in implementing
<"program", Subcomponent = yes><F7@Z7@Lam>getValues<End Sub><F0>.
This <SR>
requires conversion from internal type to strings. For many types
such as Dimension <SR>
there is no support from either Xt or Motif. However, for enumerated
types such as <SR>
arrowDirection for the ArrowButton widget, Motif 1.2 not only gives
``Representa<SR>
tion Type'' converters for conversion from String to enumerated type,
but also allows <SR>
converters in the reverse direction to be installed, so that names
such as <"program", Subcomponent = yes><F7@Z7@Lam>ar<SR>
row_left<End Sub><F0>' can be generated. This was intended for GUI
building systems which <SR>
need to use symbolic names when setting or getting widget values,
but it suits tclMotif very <SR>
well, thank you.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "10.">
<End Sub><F0>Secondary Resources
<"para">
Xt allows objects to have subobjects. There are not many examples
of these. Editors <SR>
with Output subobjects and Input subobjects are the principal ones.
The nasty part <SR>
is that these subobjects can have their own resources and Xt supplies
no means for <SR>
an application to access them. Xt has a ``hook'' to allow the toolkit
library to access <SR>
them, but not the application (in Motif at any rate they are static
to a file, so there is <SR>
no direct way of accesing them). Fortunately, Motif (not Xt) supplies
the function <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>XmGetSecondaryResources
<End Sub><F0> to get these.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "11.">
<End Sub><F0>Callback Information
<"para">
In the Motif callbacks, a rich amount of information is conveyed through
the call_data argument. Each call_data structure contains a number of
fields with information specific to the type of widget and the reason
the callback was called. For example, the List widget contains a reason
field with possible values of XmCR_SINGLE_SELECT, XmCR_EXTENDED_SELECT,
XmCR_BROWSE_SELECT, etc. Additional fields give the item selected, the
the selected item position, list of items selected, their positions,
and the number of items. Other useful information contained in a
callback includes the widget. These are accessible to the tcl code
declared to the callback by substitutions based on simple patterns.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "11.">
<End Sub><F0>Text Verify Callbacks
<"para">
Motif callbacks, as discussed, provide extra information through the
callback data structures.
Generally these structures contain ``read
only'' informa<SR>
tion that is not to be modified. These can be passed by value by just
substitution of the value.
<"para">
The Text widget has a set of ``verify'' callbacks that point to read/write
structures. <SR>
The purpose of these is to allow for things such as password entry,
where the applica<SR>
tion needs to be given the characters typed in, but must be able to
signal to Text not <SR>
to echo these characters. This is done by setting the
<"program", Subcomponent = yes><F7@Z7@Lam>doit<End Sub><F0> field
in the <"program", Subcomponent = yes><F7@Z7@Lam>XmTextVer<SR>
ifyCallbackStruct<End Sub><F0> to <"program", Subcomponent = yes><F7@Z7@Lam>Fal
se<End Sub><F0>. These callbacks are actually called by Motif in <SR>
a slightly unusual way: for example, when characters are typed in
Motif decodes the <SR>
characters, calls the <"program", Subcomponent = yes><F7@Z7@Lam>modifyVerifyCal
lbacks<End Sub><F0>, examines the return state of the <SR>
callback structure and only then actually inserts (or not) the characters
typed.
<"para">
This is handled by creating a variable global in the tcl interpreter
and passing its name <SR>
(rather than its value) into the callback. The application can then
modify its value, <SR>
and this is used to set the Motif fields as appropriate. The Motif
mechanism is odd <SR>
in this respect, and the tcl binding shows this in practice. Since
the variable is only <SR>
defined in the tcl intrepreter it does not prevent multiple interpreters
running.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "11.">
<End Sub><F0>Other Handlers
<"para">
The Intrinsics allow a number of other ways of controlling applications,
through timers, input handlers and action control. These are all dealt
with in tclMotif by registering generic handlers which take arbitrary
tcl code and call it as appropriate.
For example, Motif popup menus require a popup action to be triggered
when button 3 is pressed. This popup action must take the event that
caused it to be used to position the menu. This is done in tclMotif by
defining a translation to invoke the action:
<"para">
$w setValues -translations \<HR>
<Tab>"<<Btn3Down>: action(popit %event)
<"para">
Similarly, an input handler is added by
<"para">
. addInput file.txt r readInput
<"para">
and a timer by
<"para">
. addTimer 1000 quit
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "11.">
<End Sub><F0>Convenience functions
<"para">
Motif supplies convenience functions of several
types. <SR>
Some such as the various RowColumn functions of
<"program", Subcomponent = yes><F7@Z7@Lam>XmCreateMenuBar
<End Sub><F0>, <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>XmCreateOptionMenu
<End Sub><F0>, etc just set extra parameters for RowColumn and are <SR>
easy to handle. Two other sets are the ScrolledObject functions such
as <"program", Subcomponent = yes><F7@Z7@Lam>XmCrea<SR>
teScrolledList<End Sub><F0> and <"program", Subcomponent = yes><F7@Z7@Lam>XmCre
ateScrolledText<End Sub><F0> and the Dialog conve<SR>
nience functions such as <"program", Subcomponent = yes><F7@Z7@Lam>XmCreateForm
Dialog<End Sub><F0> etc. Both of these sets of func<SR>
tions create a pair of widgets, not just a single one. For example,
<"program", Subcomponent = yes><F7@Z7@Lam>XmCreateS<SR>
crolledList<End Sub><F0> creates a ScrolledWindow parent and the List
child, whereas the <SR>
Dialog functions create a Popup shell parent. In all cases, the Create
function returns <SR>
the child widget.
<"para">
The intent in Motif was to hide the parent widgets. Unfortunately
it canot be done <SR>
completely for several reasons. Firstly, when the ScrolledList (or
any of the others) <SR>
is destroyed, it is the parent that must be destroyed, not just the
child. Otherwise a <SR>
<|,"5">memory leak occurs. Secondly, when you need to set constraint
resources (such as <SR>
placing the ScrolledList into a Form), it is the parent widget that
needs resources set, <SR>
not the child. Thus a mechanism to access the parent is required.
<"para">
In Motif, this may be done by the call <"program", Subcomponent = yes><F7@Z7@Lam>
XtParent<End Sub><F0>, which returns the Xt widget par<SR>
ent. In this binding it is neccessary to return a tcl widget parent,
and this may be a <SR>
problem. The tcl parent must be generated automatically, but must
be guaranteed <SR>
unique. Otherwise there may be an accidental name collision with other
tcl widgets. <SR>
The Motif naming mechanism (tacking ``SW'' onto Scrolled Objects,
``_popup'' <SR>
onto dialogs) does not guarantee this. Fortunately, the particular
naming syntax used <SR>
in this binding (based on Tk), where widget names are separated by
dots ``.'' does <SR>
allow this, by inserting an extra dot. For example,
<"program">
scrolledList .l<HR>
puts stdout [.l parent]
<"para">
produces the unique `..l''.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "12.">
<End Sub><F0>Inconsistencies and Problems
<"subsection">
Actions
<"para">
tcl is designed so that multiple interpreters can be created and run
together. All information is contained in one data structure per
interpreter, that is passed into each `C' function. tclMotif attempts
to follow this pattern. This means avoiding global variables and
registering information with either with the tcl interpreter or in
such a way that it and the tcl interpreter are accessible.
<"para">
For callback functions this is easy: when a callback
is registered the client_data field is set to a structure that contains the
interpreter as well a sthe tcl command. This allows the per interpreter
information to be carried into the callback functions.
<"para">
When an action function is registered, there is no client data field to
pass the interpreter by. There is only the widget and the action function
itself. Fortunately, Motif offers a solution in that each Motif widget
contains an XmNuserData resource that can be used to store arbitrary data.
This is used in tclMotif to store a structure including the tcl interpreter,
so that all necessary information can be retrieved. This does have
the drawback that this restricts use of this system to the Motif widget
set, or to a set based on it. The WAFE system uses global variables
to handle the Athena set. There is another storage mechanism: the Context
manager of Xlib, but this requires windows to be in existence, which in
turn would require realized widgets. This cannot always be guaranteed.
<"subsection">
Tables
<"para">
By and large tcl and Motif work well together. One area that does
not integrate per<SR>
fectly concerns tables. In Motif there are sometimes tables of
<"program", Subcomponent = yes><F7@Z7@Lam>XmStrings<End Sub><F0>,
and when <SR>
they are represented as strings individual elements are separated
by commas. tcl on <SR>
the other hand represents lists as elements separated by whitespace.
Both handle lists <SR>
containing whitespace in different ways, with the tcl solution being
more general. (X11R6 looks set to introduce a third convention into
this, with StringTables of strings separated by spaces.)<SR>
Motif would have (say for a list of authors of Motif books)
<"program">
Dan Heller, Jan Newmarch, Thomas Berlage
<"para">
tcl would have
<"program">
{Dan Heller} {Jan Newmarch} {Thomas Berlage}
<"para">
An arbitrary convention has to be chosen. Currently this follows the
Motif style, but may change to the tcl style in a later version.
<"subsection">
Timing conversions
<"para">
Some resources can only be set at creation time. Such resources are
of two types: the <SR>
first is exemplified by the colormap in which the value of this resource is
used during the Initial<SR>
ize function and is thereafter unused. The second is one that cannot
be changed be<SR>
cause it has too many ramifications. Such a resource is the
<"program", Subcomponent = yes><F7@Z7@Lam>ScrollingPolicy
<End Sub><F0> of <SR>
the ScrolledWindow widget. These resources must be converted from
their String <SR>
value to be used in the <"program", Subcomponent = yes><F7@Z7@Lam>Args
<End Sub><F0> array to the <"program", Subcomponent = yes><F7@Z7@Lam>XmCreate..
.<End Sub><F0> function.
<"para">
On the other hand, some resources use widget values in their calculation.
For exam<SR>
ple, any <"program", Subcomponent = yes><F7@Z7@Lam>Dimension
<End Sub><F0> or <"program", Subcomponent = yes><F7@Z7@Lam>Position
<End Sub><F0> resource such as the <"program", Subcomponent = yes><F7@Z7@Lam>wi
dth<End Sub><F0> uses the Motif <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>UnitType<End Sub><F0> resource
in its calculation, in order to gain independance of the display <SR>
size characteristics. Similarly, the <"program", Subcomponent = yes><F7@Z7@Lam>
LabelPixmap<End Sub><F0> resource of Labels needs to have <SR>
a foreground and background before it can be created.
<"para">
These differing cases cause a problem. The convertor functions from
String to Value <SR>
use a widget parameter, and in the first case this can only be the
parent (as the child <SR>
Create function cannot have been called yet) whereas in the second
it requires the <SR>
widget itself. The special case code to handle this is not only a
maintainance problem, <SR>
but is not guaranteed to be correct in the first place as neither
Motif nor Xt offer any <SR>
support to distinguish the cases (an early version of the WKSH also
faced this problem <SR>
and missed the <"program", Subcomponent = yes><F7@Z7@Lam>LabelPixmap
<End Sub><F0> case, probably because it is quite well hidden in the <SR>
Motif source).
<"para">
This binding divides the resources into ones which must be converted
before cre<SR>
ation, those that must be converted after creation, and those for
which it does not mat<SR>
ter. These are all handled correctly. A case which is not handled
is where the conver<SR>
sion must be done <F4@Z7@Lam>during<F0> creation. Fortunately this
does not occur, as it would break <SR>
any bindings such as this one that rely on the resource converter
mechanism.
<"subsection">
XmStringTables
<"para">
Various widgets such as ScrolledList use <"program", Subcomponent = yes><F7@Z7@Lam>
XmStringTables<End Sub><F0>, which are arrays of <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>XmStrings<End Sub><F0>.
Motif is inconsistent in its internal use of these arrays - sometimes <SR>
they are NULL-terminated, most times they are not. This means that
there is no way <SR>
<|,"6">of determining from the <"program", Subcomponent = yes><F7@Z7@Lam>XmStri
ngTable<End Sub><F0> itself exactly how many elements it con<SR>
tains. This must be found from other means. For example, the size
of the List resource <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>items<End Sub><F0> is found
in the List resource <"program", Subcomponent = yes><F7@Z7@Lam>itemCount
<End Sub><F0>, and the size of the <"program", Subcomponent = yes><F7@Z7@Lam>se
lectedI<SR>
tems<End Sub><F0> resource is found in the <"program", Subcomponent = yes>
<F7@Z7@Lam>`selectedItemsCount<End Sub><F0> resource. When an <SR>
<"program", Subcomponent = yes><F7@Z7@Lam>XmStringTable<End Sub><F0>
is converted into a <"program", Subcomponent = yes><F7@Z7@Lam>String
<End Sub><F0>, this size must be known to the re<SR>
source converter. This could be determined from the widget type and
resource name <SR>
(eg for <"program", Subcomponent = yes><F7@Z7@Lam>items<End Sub><F0>
of a List widget, determine it from <"program", Subcomponent = yes><F7@Z7@Lam>i
temCount<End Sub><F0>), but the resource <SR>
name is not available to the resource converter. Thus special case
code must be in<SR>
serted before any resource converter can be called, just in case
it is one of these cases. <SR>
This is inelegant and an overhead in time for all of the resource
conversions, whatev<SR>
er type.
<"subsection">
Drag and drop
<"para">
The Motif 1.2 drag and drop model is extremely complex. It uses complex
informa<SR>
tion flows and even utilises a data structure <"program", Subcomponent = yes>
<F7@Z7@Lam>XmDropSite<End Sub><F0> that is neither a widget <SR>
nor an Xt object. It is impossible to keep interpreter information
hidden as the <SR>
XmDropSite data structure does not contain a <"program", Subcomponent = yes>
<F7@Z7@Lam>user_data<End Sub><F0> field. Use of a temporary <SR>
global variable here is a kludge, but does not seem to be a dangerous
one.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "13.">
<End Sub><F0>Hiding Complexity
<"para">
One of the hurdles in any Xt program is the complexity of concepts
in even a trivial <SR>
program. For example, the function <"program", Subcomponent = yes><F7@Z7@Lam>Xt
AppInitialize<End Sub><F0> has <F4@Z7@Lam>nine<F0> parameters, <SR>
most of which do not change from program to program. The tclMotif
library can hide <SR>
much of this complexity by supplying reasonable defaults that can
be overridden if <SR>
needed by options to tcl commands.
<"para">
Motif adds further layers of complexity above this. A particularly
tricky hurdle to <SR>
overcome is the support for internationalisation offered by
<"program", Subcomponent = yes><F7@Z7@Lam>XmStrings<End Sub><F0>.
The tclMotif <SR>
library handles XmStrings internally, and uses the normal tcl String
mechanism for <SR>
all purposes. Thus this mechanism is hidden from the tcl programmer.
It is still pres<SR>
ent in Motif, so a Label widget can display Japanese text as specified
in a resource <SR>
file. The ability of tcl to manage this is still in doubt (it is at
least 8-bit clean, and Tk <SR>
can use the X11 support to display ISO 8859-1 characters).
<"para">
Some example programs built with tclMotif include a version of the file
manager xmfm; xmeditor; widget tour; editres. The tcl version of xmfm
is about 700 lines. This represents the `C' version when it had about
7000 lines. The tcl version of xmeditor is about 300 lines. The `C' version
as given in the examples of the Motif distribution is about 1200 lines.
The tcl version of the Tk widget tour is about the same length. A program
which can display resources of an application, much like editres does,
uses Tk's send to communicate to the other application, and is 130 lines
long.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "14.">
<End Sub><F0>Validation
<"para">
The tclMotif library is built on Motif. Can it be certified as Motif compliant?
Well, actual<SR>
ly, no. This is basically a library into Motif, and as such must be
compliant with the <SR>
AES (Application Environment Specification). The AES details what
functions a <SR>
Motif library must make available, and this binding falls short of
that. For example, <SR>
tclMotif hides <"program", Subcomponent = yes><F7@Z7@Lam>XmStrings
<End Sub><F0> and has no explicit support for them. So it fails the
test of <SR>
``coverage'' as you can't do everything in tclMotif that you can using the
OSF C library.
<"para">
On the other hand, applications built using this library can be certified
as Motif com<SR>
pliant. Application compliance just means that <F4@Z7@Lam>out of the
elements of GUI used<F0>, these <SR>
conform to the Motif Style Guide. You can really muck up a tclMotif application
by putt<SR>
ing the menu bar at the bottom, with the Help button on the left and
even worse things, <SR>
and these will fail to give you Motif compliance, but if you aren't
that silly you will <SR>
be able to get Motif certification for applications built using tclMotif.
<"section">
<|,"8"><"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "15.">
<End Sub><F0>Wafe and WKSH
<"para">
The WKSH is a binding of the Korn Shell to Motif. It deals with the
same problems <SR>
as this binding, in that it has to convert Strings to Motif types.
It appears to use the <SR>
same mechanisms, and has run into the same problems. For example,
it handles the <SR>
Conversion versus Creation problem for resources such as width by
disallowing set<SR>
ting of such resources during creation! In this binding it is deferred
until it is valid. <SR>
The lack of support by Xt and Motif in this area is evidenced by the
failure of the <SR>
WKSH to correctly handle the <"program", Subcomponent = yes><F7@Z7@Lam>LabelPix
map<End Sub><F0> resource in its initial release.
<"para">
WKSH models itself on the syntax of the Motif C language binding.
The function <SR>
calls use the same names, such as <"program", Subcomponent = yes><F7@Z7@Lam>XmC
reateMainWindow<End Sub><F0>. The binding also part<SR>
ly preserves the positional syntax of the C language, so that a C
call
<"program">
w = XmCreateLabel(parent, name, args, argc)
<"para">
becomes
<"program">
XmCreateLabel parent w name args...
<"para">
The WKSH binding actually adds an extra argument to replace the return
value of <SR>
the function, and uses the varargs style of argument passing that
has become quite <SR>
popular within the X world. In calls with a large number of arguments,
the use of posi<SR>
tional parameters can be difficult.
<"para">
The WKSH binding follows this action/object style even further in
defining func<SR>
tions such as <"program", Subcomponent = yes><F7@Z7@Lam>XtManageChildren
<End Sub><F0> which place the action followed by arguments.
<"para">
The Wafe binding follows this same principle of action followed by
object, but with<SR>
out the positional argument complexity of WKSH. This particular binding
seems to <SR>
have suffered confused press in that it produces a Tcl binding to
Xt on one side, and <SR>
an open-ended binding of Tcl/Xt to almost any language on the other.
This generality <SR>
seems to have led to impressions such as ``it is a way of writing
Perl programs that <SR>
use Tcl to talk to Xt''. The current status of Wafe is that it binds
Tcl to a variety of <SR>
Xt-based widget libraries, with Athena being well supported, and Motif
in beta. The <SR>
Wafe callback model is very different to tclMotif. In tclMotif, the Motif style
is followed in <SR>
that the callback contains useful information and helps to give the
``feel'' part of the <SR>
``look and feel'' paradigm. Wafe uses a limited set of callbacks to
produce popup dia<SR>
logs.
<"para">
In implementation, the Wafe and tclMotif systems follow very similar lines
as there is <SR>
really only one way of doing much of the binding of Xt toolkits to
string languages <SR>
such as Tcl and Ksh. The authors of Wafe suffer the problem of only
having access <SR>
to Motif 1.1 at the time of writing, so the additional aids supplied
in Motif 1.2 are not <SR>
available to them. This is a distinct drawback. I am in email correspodence
with them, <SR>
to avoid duplicating work.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "16.">
<End Sub><F0>Conclusion
<"para">
This paper has discussed a binding of tcl to Motif. A large part of
this binding is quite <SR>
trivial and follows almost automatically from the way Xt and Motif
are implemented. <SR>
Every string-based language can have a binding done in a similar way.
However, <SR>
there is still flexibility in this, particularly in the choice of
object/action versus action/<SR>
object prorgamming.
<"para">
<|,"9">This binding has shown up a number of minor bugs in Motif,
but also some design <SR>
problems in both Xt and Motif with regard to string-based languages.
Nevertheless, <SR>
there seem to be no unresolvable problems in mapping a significant
amount of Motif <SR>
into tcl.
<"section">
<"|:section", Subcomponent = yes><F0><Autonum, "section#", 1, Value = "17.">
<End Sub><F0>References
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, First = Yes, Value = "1">
]<Tab><End Sub><F0>J. K. Ousterhout, <F4@Z7@Lam>Tcl: An Embeddable
Command Lnaguage<F0>, Proc USENIX <SR>
Winter Conferenece January 1990.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "2">]<Tab>
<End Sub><F0>Jp. K. Ousterhout, <F4@Z7@Lam>An X11 Toolkit Based on
the Tcl Lnaguage<F0>, Proc USENIX <SR>
Winter Conference, January 1991.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "3">]<Tab>
<End Sub><F0>G. Neumann and S. Nusser, <F4@Z7@Lam>Wafe - an X Toolkit
Based Frontend for Applica<SR>
tion Programs in Various Programming Languages<F0>, Proc USENIX Winter <SR>
Conference, January 1993.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "4">]<Tab>
<End Sub><F0>J.S. Prendergast, <F4@Z7@Lam>Korn Shell with X Winfdows
Support<F0>, Proc USING Confer<SR>
ence, 1992.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "5">]<Tab>
<End Sub><F0>J. S. Prendergast, <F4@Z7@Lam>Using Windowing Korn Shell
for Turnkey Systems<F0>, Xhibi<SR>
tion 1992.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "6">]<Tab>
<End Sub><F0>Open Software Foundation, <F4@Z7@Lam>Application Environment
Specification<F0>, Pren<SR>
tice-Hall.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "7">]<Tab>
<End Sub><F0>R. W. Scheifler, J. Gettys and R. Newman,
<F4@Z7@Lam>X Window System - C Library and Protocol Reference
<F0>, Digital Press, 1988.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "8">]<Tab>
<End Sub><F0>P. Asente and R. Swick, <F4@Z7@Lam>X Window System Toolkit, the
Complete Programmer's Guide and Specification<F0>, Digital Press, 1990.
<"reference">
<"|:reference", Subcomponent = yes><F0>[<Autonum, "ref#", 1, Value = "9">]<Tab>
<End Sub><F0>D. Beech, <F4@Z7@Lam>IFIP Conference on Command Languages, 1979.